package cn.wolfcode.luowowo.search.service.impl;

import cn.wolfcode.luowowo.search.domain.StrategyTemplate;
import cn.wolfcode.luowowo.search.query.StrategySearchQuery;
import cn.wolfcode.luowowo.search.repository.IStrategySearchRepository;
import cn.wolfcode.luowowo.search.service.IStrategySearchService;
import cn.wolfcode.luowowo.search.vo.StatisVO;
import com.alibaba.dubbo.config.annotation.Service;
import org.apache.lucene.queryparser.xml.builders.BooleanQueryBuilder;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.aggregations.bucket.composite.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;

import java.util.*;

@Service
public class StrategySearchServiceImpl implements IStrategySearchService {

    @Autowired
    private IStrategySearchRepository repository;

    @Override
    public void save(StrategyTemplate template) {
        repository.save(template);
    }

    /*GET /luowowo_strategy/strategy/_search
    {
        "size":0,
            "aggs": {
        "themeGroup": {
            "composite": {
                "sources": [
                {
                    "id": {
                    "terms": {
                        "field": "themeId"
                    }
                }
                },{
                    "name": {
                        "terms": {
                            "field": "themeName"
                        }
                    }
                }
          ]
            }
        }
    }
    }

    "aggregations" : {
        "themeGroup" : {
          "after_key" : {
            "id" : 16,
            "name" : "家庭"
          },
          "buckets" : [
            {
              "key" : {
                "id" : 3,
                "name" : "户外"
              },
              "doc_count" : 2
            },
    */

    //分组查询公共部分
    private List<StatisVO> statisGroup(String idField, String nameField, String groupName, BoolQueryBuilder queryBuilder){
        List<CompositeValuesSourceBuilder<?>> sources = new ArrayList<>();
        //多列分组: id属性对象-id列
        TermsValuesSourceBuilder idSource = new TermsValuesSourceBuilder("id");
        idSource.field(idField);   //指定的分组列:themeId
        sources.add(idSource);
        //多列分组: id属性对象-name列
        TermsValuesSourceBuilder nameSource = new TermsValuesSourceBuilder("name");
        nameSource.field(nameField);   //指定的分组列:themeName
        sources.add(nameSource);
        //多列分组查询对象
        //参数1:分组查询结果操作名词
        //参数2:分组查询的列对象集合
        CompositeAggregationBuilder aggregationBuilder =
                new CompositeAggregationBuilder(groupName,sources);
        //DSL语句的拼接类
        NativeSearchQueryBuilder  builder = new NativeSearchQueryBuilder();
        builder.addAggregation(aggregationBuilder);   //需要准备聚合查询的语句拼接
        builder.withPageable(PageRequest.of(0, 1));  //分页显示, 此次可以不设置


        //加一个条件过滤操作:

        if(queryBuilder != null){
           //builder.withQuery(QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery("countryId", 1)));
            builder.withQuery(queryBuilder);
        }


        //执行上面拼接好DSL语句, 返回结果
        AggregatedPage<StrategyTemplate> search =
                (AggregatedPage<StrategyTemplate>) repository.search(builder.build());

        //多列分组数据解析结果对象
        InternalComposite themeGroup = search.getAggregations().get(groupName);

        //遍历结果的buckets
        List<StatisVO> list = new ArrayList();
        for (CompositeAggregation.Bucket bucket : themeGroup.getBuckets()) {
            //解析bucket 获取 主题id 主题name, 主题count
            Long id = Long.parseLong(bucket.getKey().get("id").toString());
            String name = bucket.getKey().get("name").toString();
            Long count = bucket.getDocCount();
            list.add(new StatisVO(id, name, count));
        }
        //1:分组统计个数倒序排
        //参数1:进行排序的集合
        //参数2:集合比较器, 集合中两两元素比较
        Collections.sort(list, new Comparator<StatisVO>() {
            //比较规则:返回值是int类型
            //如果返回值 > 0 表示01 > 02
            //如果返回值 = 0 表示01 = 02
            //如果返回值 < 0 表示01 < 02
            @Override
            public int compare(StatisVO o1, StatisVO o2) {
                Long ret = o2.getCount() - o1.getCount();  //倒序
                return ret.intValue();
            }
        });

        return list;
    }



    @Override
    public List<Map<String, Object>> queryThemeCommentTop10() {
        List<Map<String, Object>> ret = new ArrayList<>();
        //步骤一:------先查询主题id,主题的名称,主题的个数,放回是list集合-----------------------------
        List<StatisVO> list = this.statisGroup("themeId", "themeName", "themeGroup", null);
        //3:取前面10个即可
        if(list.size() > 10){
            list = list.subList(0, 10);
        }
        //步骤二:-------迭代步骤一中的list集合, 通过主题名称/主题id查询关联的目的地集合--------------
        //步骤三:------组装数据 List<Map<String, Object>> --------------------------------------------
        Map<String, Object>  map;
        for (StatisVO vo : list) {
            map = new HashMap<>();
            map.put("theme", vo);
            //通过主题id查询目的地集合
            List<StatisVO> dests = this.findByThemeId(vo.getId());
            map.put("dests", dests);
            ret.add(map);
        }
        return ret;
    }

    //通过主题id查询目的地集合
    private List<StatisVO> findByThemeId(Long themeId) {
        List<StatisVO> list = new ArrayList<>();
        List<StrategyTemplate> templates = repository.findByThemeId(themeId);

        //2:关联目的地需要排重
        List<String> names = new ArrayList<>();
        for (StrategyTemplate template : templates) {
            String name = template.getDestName();
            if(!names.contains(name)){
                list.add(new StatisVO(template.getDestId(), template.getDestName(), null));
                names.add(name);
            }
        }
        return list;
    }


    @Override
    public List<StatisVO> queryChinaCondition() {
        return this.statisGroup("provinceId", "provinceName", "provinceGroup", null);
    }
    @Override
    public List<StatisVO> queryAbroadCondition() {
        return this.statisGroup("countryId", "countryName", "countryGroup",
                QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery("countryId", 1)));
    }
    @Override
    public List<StatisVO> queryThemeCondition() {
        return this.statisGroup("themeId", "themeName", "themeGroup", null);
    }

    @Override
    public Page query(StrategySearchQuery qo) {
        //分页信息
        Pageable pageable  = PageRequest.of(qo.getCurrentPage() - 1, qo.getPageSize(),
                Sort.Direction.DESC, qo.getOrderBy());
        //查询条件
        TermQueryBuilder queryBuilder = null;
        if(qo.getType() ==StrategySearchQuery.CONDITION_TYPE_CHINA ){
            //国内
            queryBuilder = QueryBuilders.termQuery("provinceId", qo.getTypeValue());
        }else if(qo.getType() == StrategySearchQuery.CONDITION_TYPE_ABROAD){
            //国外
            queryBuilder = QueryBuilders.termQuery("countryId", qo.getTypeValue());
        }else if(qo.getType() == StrategySearchQuery.CONDITION_TYPE_THEME){
            //主题
            queryBuilder = QueryBuilders.termQuery("themeId", qo.getTypeValue());
        }
        if(queryBuilder != null){
            return repository.search(queryBuilder, pageable);
        }
        return repository.findAll(pageable);
    }

    @Override
    public List<StrategyTemplate> findByDestName(String destName) {
        return repository.findByDestName(destName);
    }
}
